package io.lvdaxian.mybatis17.executor.statement;

import io.lvdaxian.mybatis17.executor.Executor;
import io.lvdaxian.mybatis17.executor.keygen.KeyGenerator;
import io.lvdaxian.mybatis17.executor.parameter.ParameterHandler;
import io.lvdaxian.mybatis17.executor.resultset.ResultSetHandler;
import io.lvdaxian.mybatis17.mapping.BoundSql;
import io.lvdaxian.mybatis17.mapping.MappedStatement;
import io.lvdaxian.mybatis17.session.Configuration;
import io.lvdaxian.mybatis17.session.ResultHandler;
import io.lvdaxian.mybatis17.session.RowBounds;

import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;

/**
 * 基础的statement语句的 处理器
 *
 * @author lihh
 */
public abstract class BaseStatementHandler implements StatementHandler {
  
  protected final Configuration configuration;
  protected final Executor executor;
  protected final MappedStatement mappedStatement;
  
  // 参数
  protected final Object parameterObject;
  // 执行结果处理器
  protected final ResultSetHandler resultSetHandler;
  protected BoundSql boundSql;
  
  protected final ResultHandler resultHandler;
  // 表示 参数处理器
  protected final ParameterHandler parameterHandler;
  
  public BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
    this.configuration = mappedStatement.getConfiguration();
    this.executor = executor;
    this.mappedStatement = mappedStatement;
    
    // 新增判断，因为 update 不会传入 boundSql 参数，所以这里要做初始化处理
    if (boundSql == null) {
      generateKeys(parameterObject);
      boundSql = mappedStatement.getBoundSql(parameterObject);
    }
    
    this.boundSql = boundSql;
    
    this.parameterObject = parameterObject;
    // 这是一个参数处理器
    this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
    
    // 这是一个返回值 处理器
    this.resultHandler = resultHandler;
    // 返回值 设置处理器
    this.resultSetHandler = this.configuration.newResultSetHandler(executor, mappedStatement, rowBounds, resultHandler, boundSql);
  }
  
  @Override
  public Statement prepare(Connection connection) throws SQLException {
    Statement statement;
    
    try {
      statement = instantiateStatement(connection);
      
      // 这里可以针对 statement 设置参数
      statement.setQueryTimeout(350);
      statement.setFetchSize(10000);
      
      return statement;
    } catch (Exception e) {
      e.printStackTrace();
    }
    
    return null;
  }
  
  /*
   * 该方法实际的交给 继承类来实现
   *
   * @param connection 连接
   * @return 返回  statement
   * @throws SQLException 异常
   * @author lihh
   */
  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
  
  protected void generateKeys(Object parameter) {
    KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
    keyGenerator.processBefore(executor, mappedStatement, null, parameter);
  }
  
  @Override
  public BoundSql getBoundSql() {
    return boundSql;
  }
}
